/**  
* @Title: CustomizedRedisCache.java
* @Package com.lemon.conf.redis.custom
* @Description: (一句话阐述):
* @author Ran_cc
* @date 2018年5月28日
* @version V1.0  
*/
package com.lemon.conf.redis.custom;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.core.RedisOperations;

import com.lemon.conf.content.SpringContextUtil;
import com.lemon.conf.content.ThreadTaskHelper;

/**
 * <p>
 * Title:
 * </p>
 * <p>
 * Description: 管理即将过期时间的缓存数据,重新刷新缓存数据
 * </p>
 * <p>
 * Company:
 * </p>
 * 
 * @author Ran_cc
 * @date 2018年5月28日
 * @版本 V 1.0
 */
public class CustomizedRedisCache extends RedisCache {

	private static Logger log = LoggerFactory.getLogger(CustomizedRedisCache.class);

	private static RedisOperations<String, String> redisOperations;
	private long preloadTime = 30L;

	private String cacheNames; //完整的cacheName  是注解中的cacheNames的值或者value的值
	private static final Lock REFRESH_CACKE_LOCK = new ReentrantLock();


	private static CacheSupport getCacheSupport() {
		ApplicationContext applicationContext = SpringContextUtil.getApplicationContext();
		CacheSupport bean = applicationContext.getBean(CacheSupport.class);
		return bean;
	}

	/**
	 * @Title: CustomizedRedisCache
	 * @Description:
	 * @param preloadSecondTime 刷新时间(即缓存过期时间到刷新时间的时候自动去刷新缓存)
	 * @param ro
	 * @param name              准确的cachename as:user#50#50 中的 user
	 * @param cacheWriter
	 * @param cacheConfig
	 * @param cacheName         完整的cacheName as: user#50#50
	 * @author Ran_cc
	 * @date 2018年5月28日
	 */
	protected CustomizedRedisCache( String name, RedisCacheWriter cacheWriter, RedisCacheConfiguration cacheConfig,
			RedisOperations<String, String> ro, long preloadSecondTime, String cacheName ) {
		super(name, cacheWriter, cacheConfig);
		redisOperations = ro;
		preloadTime = preloadSecondTime;
		cacheNames = cacheName;
	}

	//重写cache 的put 方法
	/*
	 * @Override
	 * public void put(Object key, @Nullable Object value) {
	 * }
	 */


	/**
	 * <p>
	 * Title: get
	 * </p>
	 * <p>
	 * Description:(一句话阐述): 判断过期时间, 在刷新时间范围内,将开启一个线程去请求接口
	 * <br>
	 * 这样做的好处就是可以缓解数据库压力,每次只请求一次, 保证用户的命中率 <br>
	 * 刷新缓存之后将缓存时间更新到最新的, 也就是cachename中的#号后面的时间
	 * </p>
	 * 
	 * @param key
	 * @return
	 * @author Ran_cc
	 * @date 2018年5月29日
	 */
	public ValueWrapper get( final Object key ) {
		ValueWrapper valueWrapper = super.get(key);
		if (null != valueWrapper) {
			long preLoadTimeSecond = preloadTime;
			String cacheKey = this.createCacheKey(key);
			Long ttl = CustomizedRedisCache.redisOperations.getExpire(cacheKey);   //获取缓存过期时间的剩余时间
			log.info("剩余TTL:【{} 】, 指定刷新TTL【{}】,Redis-Key:【{}】," , ttl , preLoadTimeSecond , cacheKey);
			if (null != ttl && ttl <= preLoadTimeSecond) {
				//				log.info(" - key:{} ttl:{} preloadSecondTime:{}" , cacheKey , ttl , preLoadTimeSecond);
				if (ThreadTaskHelper.hasRunningRefreshCacheTask(cacheKey)) {
					log.info("do not need to refresh");
				} else {
					//					runTaskTh(cacheNames, cacheKey, key.toString());
					//开启一个线程 , 去刷新缓存
					//并将线程锁定, 其他请求阻塞
					ThreadTaskHelper.run(new Runnable() {
						@Override
						public void run() {
							try {
								REFRESH_CACKE_LOCK.lock();
								if (ThreadTaskHelper.hasRunningRefreshCacheTask(cacheKey)) {
									log.info("do not need to refresh");
								} else {
									ThreadTaskHelper.putRefreshCacheTask(cacheKey);
									cacheSupportRefreshCacheByKey(cacheNames , key.toString());
									log.info(" - refresh cacheName:{},key:{}" , cacheNames , cacheKey);
									ThreadTaskHelper.removeRefreshCacheTask(cacheKey);
								}
							} finally {
								REFRESH_CACKE_LOCK.unlock();
							}
						}
					});
				}
				//				log.info("当前cache剩余TTL:{} 少于指定刷新TTL:{},已刷新", ttl, preLoadTimeSecond);
			}
		}
		return valueWrapper;
	}
	
	/*
	 * public static void runTaskTh( String cacheNames, String cacheKey, String key ) {
	 * //开启一个线程 , 去刷新缓存
	 * //并将线程锁定, 其他请求阻塞
	 * CacheSupport cacheSupport = getCacheSupport();
	 * // cacheSupport.refreshCacheByKey(CustomizedRedisCache.super.getName(), key.toString());
	 *//**
		 * cachenames 是完整的cachenames as : user#50#50
		 *//*
			 * cacheSupport.refreshCacheByKey(cacheNames, key);
			 * }
			 */

	/**
	 * <b>Description:<blockquote> 刷新指定key
	 * </blockquote></b>
	 * 
	 * @Title: cacheSupportRefreshCacheByKey
	 * @param cacheNames
	 * @param key
	 * @author Ran_cc
	 * @date 2018年6月26日
	 */
	public static void cacheSupportRefreshCacheByKey(String cacheNames , String key) {
		CacheSupport cacheSupport = getCacheSupport();
		cacheSupport.refreshCacheByKey(cacheNames , key);
	}


	public long getPreloadTime() {
		return this.preloadTime;
	}

	public void setPreloadTime( long preloadTime ) {
		this.preloadTime = preloadTime;
	}

	public String getCacheNames() {
		return this.cacheNames;
	}

	public void setCacheNames( String cacheNames ) {
		this.cacheNames = cacheNames;
	}

}
